import asyncio
from pathlib import Path
from typing import Dict, List, Optional, Union
from rich.console import Console
from rich.progress import Progress

from .package import PackageMetadata, InstalledPackage
from .exceptions import *
from ..utils.config import Config
from ..utils.logger import setup_logger
from ..utils.helpers import calculate_checksum, ensure_dir
from ..network.downloader import Downloader
from ..network.api import PackageAPI

console = Console()

class PackageManager:
    def __init__(self, config_path: Optional[Path] = None):
        # 初始化配置
        self.config = Config(config_path)
        
        # 设置基础路径
        self.base_path = Path(self.config.get('base_path')).expanduser()
        self.setup_directories()
        
        # 初始化日志
        self.logger = setup_logger(
            'package_manager',
            self.base_path / 'logs' / 'package_manager.log',
            self.config.get('log_level', 'INFO')
        )
        
        # 初始化API客户端
        self.api = PackageAPI(
            self.config.get('repo_url'),
            self.config.get('api_key')
        )
        
        # 初始化下载器
        self.downloader = Downloader(
            timeout=self.config.get('timeout', 30),
            verify_ssl=self.config.get('verify_ssl', True)
        )
        
        # 加载已安装的包
        self.installed_packages: Dict[str, InstalledPackage] = {}
        self.load_installed_packages()

    def setup_directories(self):
        """创建必要的目录结构"""
        dirs = ['cache', 'packages', 'logs', 'temp']
        for dir_name in dirs:
            ensure_dir(self.base_path / dir_name)

    def load_installed_packages(self):
        """加载已安装的包信息"""
        packages_dir = self.base_path / 'packages'
        if not packages_dir.exists():
            return

        for pkg_dir in packages_dir.iterdir():
            if pkg_dir.is_dir():
                try:
                    metadata_file = pkg_dir / 'metadata.json'
                    if metadata_file.exists():
                        with open(metadata_file, 'r') as f:
                            metadata = PackageMetadata(**json.load(f))
                            self.installed_packages[metadata.name] = InstalledPackage(
                                metadata=metadata,
                                install_path=pkg_dir,
                                install_date=datetime.fromtimestamp(pkg_dir.stat().st_ctime),
                                status='installed',
                                files=self._get_package_files(pkg_dir)
                            )
                except Exception as e:
                    self.logger.error(f"加载包 {pkg_dir.name} 失败: {str(e)}")

    async def install(self, package_name: str, version: str = "latest") -> bool:
        """安装包"""
        try:
            with Progress() as progress:
                task = progress.add_task(f"[green]安装 {package_name}...", total=100)
                
                # 获取包信息
                pkg_info = await self.api.get_package_info(package_name, version)
                progress.update(task, advance=20)
                
                # 检查依赖
                await self._resolve_dependencies(pkg_info['dependencies'])
                progress.update(task, advance=40)
                
                # 下载包
                cache_path = self.base_path / 'cache' / f"{package_name}-{pkg_info['version']}.pkg"
                await self.downloader.download_file(
                    pkg_info['download_url'],
                    cache_path,
                    lambda p: progress.update(task, completed=40 + (p * 0.4))
                )
                
                # 验证包
                if not self._verify_package(cache_path, pkg_info['checksum']):
                    raise SecurityError("包验证失败")
                
                # 安装包
                install_path = self._install_package_files(cache_path, pkg_info)
                progress.update(task, completed=100)
                
                console.print(f"[green]成功安装 {package_name} ({pkg_info['version']})")
                return True
                
        except Exception as e:
            self.logger.error(f"安装失败: {str(e)}")
            console.print(f"[red]安装失败: {str(e)}")
            return False

    async def uninstall(self, package_name: str, force: bool = False) -> bool:
        """卸载包"""
        try:
            if package_name not in self.installed_packages:
                raise PackageManagerException(f"包 {package_name} 未安装")
            
            if not force:
                self._check_reverse_dependencies(package_name)
            
            pkg = self.installed_packages[package_name]
            
            # 执行卸载
            shutil.rmtree(pkg.install_path)
            del self.installed_packages[package_name]
            
            console.print(f"[green]成功卸载 {package_name}")
            return True
            
        except Exception as e:
            self.logger.error(f"卸载失败: {str(e)}")
            console.print(f"[red]卸载失败: {str(e)}")
            return False

    async def update(self, package_name: Optional[str] = None) -> bool:
        """更新包"""
        packages_to_update = ([package_name] if package_name 
                            else list(self.installed_packages.keys()))
        
        success = True
        for pkg_name in packages_to_update:
            try:
                if pkg_name not in self.installed_packages:
                    continue
                    
                current_pkg = self.installed_packages[pkg_name]
                latest_info = await self.api.get_package_info(pkg_name, "latest")
                
                if latest_info['version'] > current_pkg.metadata.version:
                    console.print(f"[yellow]更新 {pkg_name} "
                                f"({current_pkg.metadata.version} -> {latest_info['version']})")
                    if not await self.install(pkg_name, latest_info['version']):
                        success = False
                
            except Exception as e:
                self.logger.error(f"更新 {pkg_name} 失败: {str(e)}")
                console.print(f"[red]更新 {pkg_name} 失败: {str(e)}")
                success = False
        
        return success

    def list_packages(self, show_details: bool = False) -> None:
        """列出已安装的包"""
        if not self.installed_packages:
            console.print("[yellow]没有安装任何包")
            return
            
        table = Table(show_header=True, header_style="bold magenta")
        table.add_column("包名")
        table.add_column("版本")
        table.add_column("安装日期")
        if show_details:
            table.add_column("描述")
            table.add_column("作者")
            
        for name, pkg in self.installed_packages.items():
            row = [
                name,
                pkg.metadata.version,
                pkg.install_date.strftime("%Y-%m-%d %H:%M:%S")
            ]
            if show_details:
                row.extend([
                    pkg.metadata.description,
                    pkg.metadata.author
                ])
            table.add_row(*row)
            
        console.print(table)

    def _verify_package(self, package_path: Path, expected_checksum: str) -> bool:
        """验证包完整性"""
        actual_checksum = calculate_checksum(package_path)
        return actual_checksum == expected_checksum

    async def _resolve_dependencies(self, dependencies: Dict[str, str]) -> None:
        """解析并安装依赖"""
        for dep_name, dep_version in dependencies.items():
            if dep_name not in self.installed_packages:
                await self.install(dep_name, dep_version)
            elif not self._version_satisfies(
                self.installed_packages[dep_name].metadata.version,
                dep_version
            ):
                await self.install(dep_name, dep_version)

    def _check_reverse_dependencies(self, package_name: str) -> None:
        """检查反向依赖"""
        for name, pkg in self.installed_packages.items():
            if package_name in pkg.metadata.dependencies:
                raise DependencyError(f"包 {name} 依赖于 {package_name}")

    def _version_satisfies(self, current: str, required: str) -> bool:
        """检查版本是否满足要求"""
        # 这里需要实现版本比较逻辑
        return True  # 简化实现